-
Notifications
You must be signed in to change notification settings - Fork 144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
♻️ use playwright for e2e #3159
base: main
Are you sure you want to change the base?
Conversation
Bundles Sizes Evolution
🚀 CPU Performance
🧠 Memory Performance
|
2d0d0e3
to
ba625db
Compare
1dd0038
to
8dfc67f
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #3159 +/- ##
==========================================
- Coverage 92.96% 92.90% -0.07%
==========================================
Files 298 298
Lines 7859 7862 +3
Branches 1789 1792 +3
==========================================
- Hits 7306 7304 -2
- Misses 553 558 +5 ☔ View full report in Codecov by Sentry. |
dc360fb
to
faf30a2
Compare
894fb1b
to
959889f
Compare
test/e2e/lib/helpers/browser.ts
Outdated
test.info().annotations.push({ | ||
type: 'dd_tags[test.fixme]', | ||
description: 'Unnexpected Console log message: "Ignoring unsupported entryTypes: *"', | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This add the property @test.fixme
in CI visibility, this is very useful to create dashboards
c16ff1a
to
195bda3
Compare
0e744fa
to
77f9052
Compare
This reverts commit 77f9052.
name: 'Firefox', | ||
version: '91.0', | ||
name: 'playwright-firefox', | ||
version: '119', |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ question: What is the reasoning behind this version bump?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Older version of firefox don't work with this version of playwright.
The version we used to test was already chosen arbitrary and did not reflect the oldest version supported.
For unit tests however we test on the oldest browser version we support
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fore context: Firefox 91 was chosen because it was a ESR version. We were aware that using playwright would imply bumping a few browser versions, so using v119 looks fine to me.
flushEvents: () => flushEvents(page), | ||
deleteAllCookies: () => deleteAllCookies(browserContext), | ||
sendXhr: (url: string, headers?: string[][]) => sendXhr(page, url, headers), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ question: What qualifies a function to be in TestContext vs used standalone by invoking it with page/browserContext?
I see we have deleteAllCookies
in TestContext, but setCookie
as standalone. I feel like we would scale more with standalone functions, but at the same time things might be a bit more verbose. WDYT?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good question! Playwright encourage to use fixtures, so adding a function to TestContext fit well with Playwright style.
However, I think there is room for both:
- For heavily used functions, such as
flushEvents
,withBrowserLogs
, I think it's convenient to not have to passpage
orbrowserContext
all the time. - For function that are less often used or used only in one test file, then I think it might be better to have standalone function.
I think deleteAllCookies
is not actually a good example as it's just doing browserContext.clearCookies()
so we might use that directly.
At the end, it's a bit inconsistent in this PR as multiple people have migrated tests without clear direction.
test/e2e/lib/framework/pageSetups.ts
Outdated
'services' in browser.options && | ||
browser.options.services && | ||
browser.options.services.some((service) => (Array.isArray(service) ? service[0] : service) === 'browserstack') | ||
const isBrowserStack = process.env.BS_USERNAME && process.env.BS_ACCESS_KEY |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
❓ question: can we have a test that doesn't rely on the environment? Maybe using process.argv
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
we certainly could detect browserstack differently here, but BS_USERNAME
and BS_ACCESS_KEY
are populated as env variable anyway and used for unit-bs
job too.
I thought it would be convenient to use that as a signal test are running on BS.
test/e2e/lib/helpers/browser.ts
Outdated
const filteredLogs = this.logs.filter((log) => !log.message.includes('Ignoring unsupported entryTypes: ')) | ||
|
||
interface BrowserLog { | ||
level: string | ||
message: string | ||
source: string | ||
timestamp: number | ||
} | ||
if (filteredLogs.length !== this.logs.length) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥜 nitpick:
if (this.logs.some((log) => log.message.includes('Ignoring unsupported entryTypes: ')) {
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately, we need to actually filter out these warning message, otherwise a bunch of test are failing because they expect logs to be a certain length.
Ultimately this need to be fixed in the observer as this message is shown to customers (but this seems out of scope for this PR)
nevermind, I guess it's more readable, for little performance overhead!
test/e2e/lib/helpers/tags.ts
Outdated
test.info().annotations.push({ | ||
type: `dd_tags[test.${tag}]`, | ||
description: value, | ||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥜 nitpick: use addTag
here
test/e2e/playwright.local.config.ts
Outdated
use: { ...devices['Desktop Chrome'] }, | ||
}, | ||
{ | ||
name: 'firefox', | ||
use: { ...devices['Desktop Firefox'] }, | ||
}, | ||
{ | ||
name: 'webkit', | ||
use: { ...devices['Desktop Safari'] }, | ||
}, | ||
{ | ||
name: 'android', | ||
use: { ...devices['Pixel 7'] }, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🥜 nitpick:
use: { ...devices['Desktop Chrome'] }, | |
}, | |
{ | |
name: 'firefox', | |
use: { ...devices['Desktop Firefox'] }, | |
}, | |
{ | |
name: 'webkit', | |
use: { ...devices['Desktop Safari'] }, | |
}, | |
{ | |
name: 'android', | |
use: { ...devices['Pixel 7'] }, | |
use: devices['Desktop Chrome'], | |
}, | |
{ | |
name: 'firefox', | |
use: devices['Desktop Firefox'], | |
}, | |
{ | |
name: 'webkit', | |
use: devices['Desktop Safari'], | |
}, | |
{ | |
name: 'android', | |
use: devices['Pixel 7'], |
.run(async ({ intakeRegistry }) => { | ||
const button = await getNodeInsideShadowDom('my-scrollable-div', 'button') | ||
.run(async ({ flushEvents, intakeRegistry, page }) => { | ||
const button = page.locator('my-scrollable-div button') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👏 praise: really nice to be able to locate elements within shadow dom
const { sessionName } = test.info().project.metadata as BrowserConfiguration | ||
test.fixme(sessionName === 'Edge', 'In Edge, the ViewportResize record data is off by almost 20px') |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: we should have a single way to identify which browser is being used.
Previously, we had the getBrowserName
function that returned a normalized browser name. It returned a strongly typed constant string, making it easy to understand what to expect. Now we have (at least) three ways of getting the browser name:
testContext.browserName === 'chromium'
testContext.browserName.includes("firefox")
test.info().project.metadata.sessionName === 'Edge'
In the same spirit, I think testContext.browserName
should:
- be strongly typed, with constant strings instead of arbitrary strings
- support all browsers (firefox, edge, ...)
- normalize the names (ex:
playwright-firefox
should be normalized tofirefox
)
And we should avoid having to pick into test.info()
to get that information
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually it is normalized (here) because browserName
is a playwright property, and it's type is 'chromium' | 'firefox' | 'webkit'
About testContext.browserName.includes("firefox")
, it is a mistake, I'm fixing it to testContext.browserName === 'firefox'
👌
However, Edge browsers have chromium
for browserName
, but the viewport issue is really on Edge, not on all chromium browsers, hence this ugly trick. 😞
I guess we could normalize browserName
in TestContext differently to playwright's meaning. That would not be too much of a hassle. wdyt?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
differently to playwright's meaning
Yes, I think it would be good!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this needs to be within the e2e test suite. If it makes things more complicated, we could imagine moving it somewhere else (in a standalone script).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's actually more convenient to have it run in the e2e, we avoid setting up a separate job, script, test runner, ...
}) | ||
.then((response) => response.text()) | ||
.then(resolve) | ||
.catch(() => resolve(new Error('Fetch request failed!'))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💬 suggestion: Don't use new Promise
when you already have promises:
const rawHeaders = await page.evaluate(
() =>
window
.fetch('/headers', {
headers: [
['x-foo', 'bar'],
['x-foo', 'baz'],
],
})
.then((response) => response.text())
.catch(new Error('Fetch request failed!'))
)
(Same suggestion applies to other new Promise
in that file)
Motivation
Improve reliability and speed of our e2e tests.
Changes
We now uses Playwright as a e2e test runner. There is small changes to the API but things remains very similar.
Speed 🚀
(*) BrowserStack timing does not account for the time spend waiting for BS resources.
Playwright already allow e2e to be faster, however there is a few other optimizations:
unit-bs
ande2e-bs
jobs run as soon asunit
ande2e
jobs are finished respectively. This is so we don't wait for the slowertest-performance
job.e2e-bs
job will retry each test up to two time to be more resilient for flakiness, however, the job will stop as soon as a single test fails in order to free up browserstack resources.new useful commands:
yarn test:e2e --ui
run playwright locally in UI modeyarn test:e2e -g "unhandled rejections"
to grep tests by nameyarn test:e2e --debug
to playwright in debug modeyarn test:e2e --project firefox
to run tests in firefox. available projects:chromium
(default),firefox
,webkit
, and*
(all)yarn test:e2e --repeat-each 3
to run each test 3 times, useful for catching flaky testsBS_USERNAME=johdoe_abcD BS_ACCESS_KEY=askldjhfn yarn test:e2e:bs
to run the tests in BrowserstackImportant
yarn test:e2e
does not build the SDK automatically, runyarn build:bundle
if you have made change to the source code of the SDK.new useful method:
expect([1, 2, 3]).toHaveLength(3)
, will show a better error message when failing, including the actual array content.await page.pause()
to use with--debug
Testing
Locally, run
yarn test:e2e --ui
I have gone over the contributing documentation.